#ifndef __THREAD_POOL_H__
#define __THREAD_POOL_H__

#include <pthread.h>
#include <queue>
#include <exception>
#include <cstdio>
#include "locker.h"

// 线程池类: 模板类
template <typename T>
class ThreadPool
{
public:
    ThreadPool(int thread_number = 8, int max_requests = 10000);
    ~ThreadPool();

    bool append(T *request);

private:
    static void* worker(void* arg);
    void run();


    int m_thread_number;        // 线程最大数量
    pthread_t *m_threads;       // 线程池数组
    int m_max_requests;         // 最大任务数量
    std::queue<T *> m_workqueue; // 任务队列
    Locker m_queueLocker;       // 互斥锁
    Sem m_queuestat;            // 队列中任务数量
    bool m_stop;                   // 结束标记
};

template <typename T>
ThreadPool<T>::ThreadPool(int thread_number, int max_requests) : m_thread_number(thread_number), m_max_requests(max_requests),
                                                                 m_queuestat(0), m_stop(false), m_threads(NULL)
{
    //判断传入的参数是否正确
    if(thread_number <= 0 || max_requests <= 0) {
        throw std::exception();
    }

    //开辟线程数组内存空间
    m_threads = new pthread_t[m_thread_number];
    if(!m_threads) {
        throw std::exception();
    }

    //创建线程并分离
    for(int i = 0; i < thread_number; i++) {
        printf("正在创建第%d个线程\n", i);
        int res = pthread_create(m_threads + i, NULL, worker, this);
        if(res) {
            delete[] m_threads;
            throw std::exception();
        }

        if(pthread_detach(m_threads[i])) {
            delete[] m_threads;
            throw std::exception();
        }
    }
}

template <typename T>
ThreadPool<T>::~ThreadPool()
{
    if(m_threads) {
        delete[] m_threads;
    }
    m_stop = true;
}

template <typename T>
bool ThreadPool<T>::append(T *request)
{
    m_queueLocker.lock();
    if(m_workqueue.size() >= m_max_requests) {
        m_queueLocker.unlock();
        return false;
    }

    m_workqueue.push(request);
    m_queueLocker.unlock();
    m_queuestat.post();
    return true;
}

template <typename T>
inline void *ThreadPool<T>::worker(void *arg)
{
    ThreadPool *pool = (ThreadPool*) arg;
    pool->run();
    return pool;
}

template <typename T>
void ThreadPool<T>::run()
{
    while(!m_stop) {
        m_queuestat.wait();
        m_queueLocker.lock();
        if(m_workqueue.empty()) {
            m_queueLocker.unlock();
            continue;
        }

        T* request = m_workqueue.front();
        m_workqueue.pop();
        m_queueLocker.unlock();

        if(!request) {
            continue;
        }
        request->process();
    }
}

#endif